package com.ikas.ai.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 网络管理相关
 * @author HXH
 */
public class NetUtil {
    private static Logger logger = LoggerFactory.getLogger(NetUtil.class);

    public static void main(String[] args) {
        long time = System.currentTimeMillis();
        String ip = "10.11.97.40";
        isAddressAvailable(ip);

        long lip = ip2Long(ip);
        logger.debug("{}", lip);
        String str = long2IP(lip);
        logger.debug(str);

        long timespan = System.currentTimeMillis() - time;
        logger.debug(String.format("TIME : %d", timespan));
    }

    /**
     * 获得客户端真实IP地址.
     * @param request
     * @return
     */
    public static String getIPAddress(HttpServletRequest request) {
        String ip = null;
        String unKnow = "unknown";
        String ipAddresses = request.getHeader("X-Forwarded-For");
        if (ipAddresses == null || ipAddresses.length() == 0 || unKnow.equalsIgnoreCase(ipAddresses)) {
            ipAddresses = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || unKnow.equalsIgnoreCase(ipAddresses)) {
            ipAddresses = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || unKnow.equalsIgnoreCase(ipAddresses)) {
            ipAddresses = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || unKnow.equalsIgnoreCase(ipAddresses)) {
            ipAddresses = request.getHeader("X-Real-IP");
        }
        if (ipAddresses != null && ipAddresses.length() != 0) {
            ip = ipAddresses.split(",")[0];
        }
        if (ip == null || ip.length() == 0 || unKnow.equalsIgnoreCase(ipAddresses)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 使用正则表达式判断ip地址是否正确.
     * @param ipAddress
     * @return
     */
    public static boolean isIp(String ipAddress) {
        // 这里表示从200开始的数
        String regex0 = "(2[0-4]\\d)" + "|(25[0-5])";
        // 这里是100-200数的约定
        String regex1 = "1\\d{2}";
        // 不能以0打头的二位数
        String regex2 = "[1-9]\\d";
        // 0-9一位数
        String regex3 = "\\d";
        // 每一个点分十进数都可以取上面的值
        String regex = "(" + regex0 + ")|(" + regex1 + ")|(" + regex2 + ")|(" + regex3 + ")";
        // 加上"."
        regex = "(" + regex + ").(" + regex + ").(" + regex + ").(" + regex + ")";
        // 预编译这个正则表达式,使速度更快
        Pattern p = Pattern.compile(regex);
        // 进行匹配
        Matcher m = p.matcher(ipAddress);
        // 返回匹配结果
        return m.matches();
    }

    /**
     * 获得本机IP地址.
     * @return
     */
    public static String getIPAddress() {
        String ipAddress = "";
        // 根据网卡取本机配置的IP，适用于Windows和Linux
        Enumeration<?> netInterfaces = null;
        try {
            netInterfaces = NetworkInterface.getNetworkInterfaces();
        } catch (SocketException e) {
            logger.error(e.getMessage(), e);
        }
        if (netInterfaces == null) {
            return ipAddress;
        }
        InetAddress ip = null;
        while (netInterfaces.hasMoreElements()) {
            NetworkInterface ni = (NetworkInterface) netInterfaces.nextElement();
            String displayName = ni.getDisplayName().toLowerCase();
            Enumeration<?> inetAddress = ni.getInetAddresses();
            while (inetAddress != null && inetAddress.hasMoreElements()) {
                Object obj = inetAddress.nextElement();
                if (obj != null) {
                    ip = (InetAddress) obj;
                    // isSiteLocalAddress方法
                    // 当IP地址是地区本地地址(SiteLocalAddress)时返回true，否则返回false。IPv4的地址本地
                    // 地址分为三段：10.0.0.0 ~ 10.255.255.255、172.16.0.0 ~ 172.31.255.255、192.168.0.0
                    // ~ 192.168.255.255。IPv6的地区本地地址的前12位是FEC，其他的位可以是任意取值，
                    // 如FED0::、FEF1::都是地区本地地址。

                    // isLoopbackAddress方法
                    // 当IP地址是loopback地址时返回true，否则返回false。loopback地址就是代表本机的IP地址。
                    // IPv4的loopback地址的范围是127.0.0.0 ~ 127.255.255.255，也就是说，只要第一个字节是127，
                    // 就是lookback地址。如127.1.2.3、127.0.200.200都是loopback地址。IPv6的loopback地址是
                    // 0:0:0:0:0:0:0:1，也可以简写成::1。

                    if (!ip.isLoopbackAddress() && ip.getHostAddress().indexOf(':') == -1 && !displayName.contains("docker") && !displayName.contains("vmware")) {
                        ipAddress = ip.getHostAddress();
                        break;
                    }
                }
            }
        }
        return ipAddress;
    }

    /**
     * 获得MAC地址.
     * @return
     */
    public static String getMacAddr() {
        String macAddr = "";
        StringBuilder sb = new StringBuilder();
        try {
            InetAddress ia = InetAddress.getLocalHost();
            byte[] buf = NetworkInterface.getByInetAddress(ia).getHardwareAddress();
            for (int i = 0; i < buf.length; i++) {
                sb.append(NumUtil.byteHEX(buf[i]));
            }
            macAddr = sb.toString().toUpperCase();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return macAddr;
    }

    /**
     * 整型解析为IP地址
     * @param ip
     * @return
     */
    public static String long2IP(Long ip) {
        return String.format("%d.%d.%d.%d", (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff,
                ip & 0xff);
    }

    /**
     * 字符串ip转换为long
     * @param ip
     * @return
     */
    public static long ip2Long(String ip) {
        String[] ips = ip.split("[.]");
        return 16777216L * Long.parseLong(ips[0]) + 65536L * Long.parseLong(ips[1])
                + 256 * Long.parseLong(ips[2]) + Long.parseLong(ips[3]);
    }

    public static void isAddressAvailable(String ip) {
        try {
            InetAddress address = InetAddress.getByName(ip);
            // ping this IP

            if (address instanceof java.net.Inet4Address) {
                logger.debug(ip + " is ipv4 address");
            } else if (address instanceof java.net.Inet6Address) {
                logger.debug(ip + " is ipv6 address");
            } else {
                logger.debug(ip + " is unrecongized");
            }

            if (address.isReachable(5000)) {
                logger.debug("SUCCESS - ping " + ip + " with no interface specified");
            } else {
                logger.debug("FAILURE - ping " + ip + " with no interface specified");
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }
}
